
#include <iostream.h>
#include "classFLOBOSS.h"
#include "MacrosPorts.h"




/****************************************************************************************************/
/*                  S U P E R     H I G H     P U B L I C      F U N C T I O N S                    */
/****************************************************************************************************/
bool FLOBOSS::GetCurrentParameters(GFGdata *pCurrData)
{ uint cikl;
//
  (*pCurrData).Time.mnth = 0;
  for(cikl=5; cikl; --cikl)
    { 
      AskOpcode7(&((*pCurrData).Time));
      if( (*pCurrData).Time.mnth>0 && (*pCurrData).Time.mnth<13 ) break;
     }
  AskOpcode180(T_Point, &((*pCurrData).T), 4);
  AskOpcode180(P_Point, &((*pCurrData).P), 4);
  AskOpcode180(Qs_Point, &((*pCurrData).Q), 4);
  AskOpcode180(Qr_Point, &((*pCurrData).Qsum), 4);
  (*pCurrData).Err = Error;
  if(Error) {return false;} else {return true;}
}


bool FLOBOSS::GetGasPassport(GASpassport *pPass)
{ uint cikl;
//
  for(cikl=5; cikl; --cikl)  { AskOpcode180(Pbar_Point, &((*pPass).Pbar), 4);   if(!Error) break; }
  AskOpcode180(Ro_Point, &((*pPass).Rhoc), 4);
  AskOpcode180(N2_Point, &((*pPass).N2val), 4);
  AskOpcode180(CO2_Point, &((*pPass).CO2val), 4);
  (*pPass).err = Error;
  if(Error) {return false;} else {return true;}
}




char FLOBOSS::GetArMP(DataTime *pData, FBarch *pArD, char NofRecs)
{ IndxHi = 840; IndxLo = 0;     return ReadArchive(pData,pArD,NofRecs); }


char FLOBOSS::GetArDay(DataTime *pData, FBarch *pArD)
{ 
  IndxHi = 876; IndxLo = 840; (*pData).hour = (*pData).min = (*pData).sec = 0;
  return ReadArchive(pData,pArD,1);
}

bool FLOBOSS::PutCO2(float CO2percent)
{
  AskOpcode181(CO2_Point,&CO2percent,4);
  if(Error) {return false;} else {return true;}
}


bool FLOBOSS::PutN2(float N2percent)
{
  AskOpcode181(N2_Point,&N2percent,4);
  if(Error) {return false;} else {return true;}
}

bool FLOBOSS::PutRhoc(float RhocVal)
{
  AskOpcode181(Ro_Point,&RhocVal,4);
  if(Error) {return false;} else {return true;}
}

bool FLOBOSS::PutPbar(float PbarVal)
{
  AskOpcode181(Pbar_Point,&PbarVal,4);
  if(Error) {return false;} else {return true;}
}






char FLOBOSS::ReadArchive(DataTime *pData, FBarch *pArD, char NofRecs)
{ 
  usht IndxHbefor, IndxHafter, IndxH;  char NofRec=0;
  uint cikl, DataBgn, DataEnd;  
//  
  for(cikl=5; cikl; --cikl)   { AskOpcode120(&IndxHbefor); if(IndxHbefor!=65535) break; }
//
///  IndxHi = 840; IndxLo = 0;
  if(ContractHour==24) AskOpcode180(Hour_Point, &ContractHour, 1);
  DataBgn = ((uint)(*pData).mnth<<24)+((uint)(*pData).date<<16)+((uint)(*pData).hour<<8)+(*pData).min;
  DataEnd = CalcEndOfDay(DataBgn,ContractHour);
  IndxH = RecordScan(IndxHbefor,DataBgn,DataEnd);
//
  if(IndxH>=IndxLo && IndxH<IndxHi)
   {
     NofRec = ReadArchData(IndxH,NofRecs,DataEnd,pArD);
     ReadArchVals(IndxH,NofRecs,P_PointH,(char*)&((*pArD).P),sizeof(FBarch));
     ReadArchVals(IndxH,NofRecs,T_PointH,(char*)&((*pArD).T),sizeof(FBarch));
     ReadArchVals(IndxH,NofRecs,K_PointH,(char*)&((*pArD).K),sizeof(FBarch));
     ReadArchVals(IndxH,NofRecs,Vr_PointH,(char*)&((*pArD).Vr),sizeof(FBarch));
     ReadArchVals(IndxH,NofRecs,Vc_PointH,(char*)&((*pArD).Vc),sizeof(FBarch));
     //
     AskOpcode120(&IndxHafter);
     if(IndxHafter!=65535) cikl = CheckReWrite(IndxH,IndxHbefor,IndxHafter);
     FillNoData(cikl,pArD); pArD += cikl; NofRecs -= NofRec; NofRec -= cikl; cikl=  NofRec;
     while(cikl) { (*pArD).AD.yy = (*pData).year; ++pArD; --cikl; }
    }
  FillNoData(NofRecs,pArD);   
  return NofRec;
}









uint FLOBOSS::CalcEndOfDay(uint Data, uint Hour)
{ Hour <<= 8; if((Data&0x0000FF00) >= Hour) Data += (1<<16);  return Data&0xFFFF0000|Hour|1; }

usht FLOBOSS::RecordScan(usht IndxB, uint DataBgn, uint DataEnd)
{ char NofVals; usht Indx, IndxOK=65535;
  Indx = IndxB+1; if(Indx==IndxHi) Indx = IndxLo;
  while(Indx!=IndxB)
   {
     if(Indx<IndxB)
       { if(IndxB-Indx<60) {NofVals = IndxB-Indx;} else {NofVals = 60;} }
      else
       { if(IndxHi-Indx<60) {NofVals = IndxHi-Indx;} else {NofVals = 60;} }
     if(AskOpcode130(254,NofVals,Indx)) IndxOK = DataCheck(DataBgn,DataEnd,NofVals);
     if(IndxOK!=65535) {IndxOK += Indx; break;}
     Indx += NofVals; if(Indx==IndxHi) Indx = IndxLo;
    }
  return IndxOK;
}

uint FLOBOSS::CheckReWrite(uint I, uint Ibefor, uint Iafter)
{
  if(Ibefor<Iafter)
    { if(I>Ibefor && I<=Iafter) return Iafter-I+1; }
   else if(Ibefor>Iafter)
    {
      if(I>Ibefor) return Iafter+IndxHi-IndxLo-I+1;
      if(I<=Iafter) return Iafter-I+1;
     }
  return 0;
}


void FLOBOSS::FillNoData(uint NofRec, FBarch *pArD)
{
  while(NofRec)
   {
     (*pArD).AD.sec=(*pArD).AD.min=(*pArD).AD.hh=(*pArD).AD.dd=(*pArD).AD.mm=(*pArD).AD.yy=0;
     (*pArD).P=(*pArD).T=(*pArD).K=(*pArD).Vr=(*pArD).Vc=0;   (*pArD).Err = erNAR;
      ++pArD; --NofRec;
    }
}

char FLOBOSS::ReadArchData(uint Indx, uint NofRec, uint DataEnd, FBarch *pArD)
{ uint NofVals, Data, DataOld=0, ui1; char NofRecs=0;
//
  while(NofRec)
   {
     if(IndxHi-Indx<NofRec) {NofVals = IndxHi-Indx;} else {NofVals = NofRec;}
     if(AskOpcode130(254,NofVals,Indx))
       {
         InStrt = (*pUx).shift(InStrt,9);
         for(ui1=0; ui1<NofVals; ++ui1)
          {
            GetValue((*pUx).shift(InStrt,ui1<<2),&Data,4);
            if(Data>=DataOld && Data<DataEnd)
              {
                (*pArD).AD.sec = 0;  (*pArD).AD.min = (char)Data;  (*pArD).AD.hh = (char)(Data>>8);
                (*pArD).AD.dd = (char)(Data>>16);  (*pArD).AD.mm = (char)(Data>>24);
                ++pArD; DataOld = Data; ++NofRecs;
               }
            else {NofRec = ui1; break;}
          }
         Indx += ui1; if(Indx==IndxHi) Indx = IndxLo;
         NofRec -= ui1;
        }
      else {NofRec = 0;}
    }
  return NofRecs;
}


void FLOBOSS::ReadArchVals(uint IndxBgn, char NofRec, char PointH, char *pVal, uint shift)
{ uint NofVals,  ui1;
//
  while(NofRec)
   {
     if(IndxHi-IndxBgn<NofRec) {NofVals = IndxHi-IndxBgn;} else {NofVals = NofRec;}
     if(AskOpcode130(PointH,NofVals,IndxBgn))
       {
         InStrt = (*pUx).shift(InStrt,9);
         for(ui1=0; ui1<NofVals; ++ui1)
          { GetValue((*pUx).shift(InStrt,ui1<<2),pVal,4);  pVal += shift; --NofRec; }
         IndxBgn += NofVals; if(IndxBgn==IndxHi) IndxBgn = IndxLo;
        }
      else {NofRec = 0;}
    }
}



usht FLOBOSS::DataCheck(uint DataBgn, uint DataEnd, char NofVals)
{ uint DataLo, DataHi, DataMd, indxLo, indxHi, indxMd;
//
  InStrt = (*pUx).shift(InStrt,9);
  indxLo = 0; indxHi = NofVals-1;
  GetValue(InStrt,&DataLo,4);  GetValue((*pUx).shift(InStrt,indxHi<<2),&DataHi,4);
//
  if(DataLo<=DataHi)
    { if(DataBgn>DataHi || DataBgn<DataLo) return 65535; }
   else
    { if(DataBgn>DataHi && DataBgn<DataLo) return 65535; }
//
  while(indxHi-indxLo>1)
   {
     indxMd = indxHi+indxLo>>1;
     GetValue((*pUx).shift(InStrt,indxMd<<2),&DataMd,4);
     if(DataMd>DataBgn) {DataHi=DataMd; indxHi=indxMd;} else {DataLo=DataMd; indxLo=indxMd;}
    }
//
  if(DataBgn==DataLo) return indxLo;
  if(DataHi>=DataBgn && DataHi<DataEnd) {return indxHi;} else {return 65535;}
}

/****************************************************************************************************/
/*                             P U B L I C      F U N C T I O N S                                   */
/****************************************************************************************************/

FLOBOSS::FLOBOSS(UARTbuf *pUART, char ROC_unit, char ROC_group)
{
  pUx = pUART; (*pUx).setCR16InitVal(0);
  ROCunit = ROC_unit;  ROCgroup = ROC_group;  HOSTunit = HOSTunitDefault; HOSTgroup = HOSTgroupDefault;
  OpID[0] = 'L'; OpID[1] = 'O'; OpID[2] = 'I'; Password = 1000;  ContractHour = 24;
}
/****************************************************************************************************/










/****************************************************************************************************/

void FLOBOSS::AskOpcode6(void)
{  FormOpcode6();     if(askFLOBOSS()) {CheckError();}  }




void FLOBOSS::AskOpcode7(DataTime *pDT)
{
  FormOpcode7();
  if( askFLOBOSS() )
    {
      CheckError();
      if(!Error) {GetTime((*pUx).shift(InStrt,6),pDT);}  else  {RstTime(pDT);} 
     }
   else
    { RstTime(pDT); Error = erNAN; } 
  
  
}


void FLOBOSS::AskOpcode17(void)
{  FormOpcode17();  if(askFLOBOSS()) {CheckError();} else {Error = erNAN;}  }


void FLOBOSS::AskOpcode120(usht *pIndx)
{
  FormOpcode120();
  if( askFLOBOSS() )
    {
      CheckError();
      if(!Error) 
        {
          if(IndxHi==840)
            { GetValue((*pUx).shift(InStrt,10),(char*)pIndx,2); }
           else
            { GetValue((*pUx).shift(InStrt,18),(char*)pIndx,2); *pIndx += IndxLo; }
         }
       else
        { *pIndx = 65535; } 
     }
   else
    { *pIndx = 65535; Error = erNAN; } 
//
}


bool FLOBOSS::AskOpcode130(char HPointNum, char NofVals, usht StrtPointer)
{
  if(NofVals>60) return false;
  FormOpcode130(HPointNum,NofVals,StrtPointer);
  if( askFLOBOSS() )
    { CheckError(); if(!Error) {return true;} else {return false;} }
   else
    { Error = erNAN; return false; } 
}





void FLOBOSS::AskOpcode180(uint Point, void *pVar, char Nbytes)
{
  if(Nbytes!=1 && Nbytes!=2 && Nbytes!=4) return;
  FormOpcode180(Point);
  if( askFLOBOSS() )
    {
      CheckError();
      if(!Error) 
        {GetValue((*pUx).shift(InStrt,10),(char*)pVar,Nbytes);}
       else
        {RstValue((char*)pVar,Nbytes);} 
     }
   else
    { RstValue((char*)pVar,Nbytes); Error = erNAN; } 
//
}


void FLOBOSS::AskOpcode181(uint Point, void *pVar, char Nbytes)
{
  if(Nbytes!=1 && Nbytes!=2 && Nbytes!=4) return;
  FormOpcode181(Point,(char*)pVar,Nbytes);
  if(askFLOBOSS()) {CheckError();} else {Error = erNAN;} 
}


/****************************************************************************************************/
/*                            P R I V A T E      F U N C T I O N S                                  */
/****************************************************************************************************/


void FLOBOSS::FormOpcode6(void)
{ uint Ibgn = formAddress();     wrChar(6); wrChar(0);     (*pUx).CRC16out(Ibgn); }
/****************************************************************************************************/


void FLOBOSS::FormOpcode7(void)
{ uint Ibgn = formAddress();     wrChar(7); wrChar(0);     (*pUx).CRC16out(Ibgn); }
/****************************************************************************************************/


void FLOBOSS::FormOpcode17(void)
{ 
  uint Ibgn = formAddress();
  wrChar(17); wrChar(6); 
  wrChar(OpID[0]); wrChar(OpID[1]); wrChar(OpID[2]);
  wrChar(Password); wrChar(Password>>8);
  wrChar(AccessLevel);
  (*pUx).CRC16out(Ibgn);
}
/****************************************************************************************************/

void FLOBOSS::FormOpcode120(void)
{  uint Ibgn = formAddress();     wrChar(120); wrChar(0);   (*pUx).CRC16out(Ibgn);  }
/****************************************************************************************************/



void FLOBOSS::FormOpcode128(char HPointNum, char month, char day)
{ 
  uint Ibgn = formAddress();     wrChar(128); wrChar(3); 
  wrChar(HPointNum);  wrChar(day);  wrChar(month); 
  (*pUx).CRC16out(Ibgn);
}
/****************************************************************************************************/

void FLOBOSS::FormOpcode130(char HPointNum, char NofVals, usht StrtPointer)
{ 
  uint Ibgn = formAddress();     wrChar(130); wrChar(5); 
  wrChar(0);
  wrChar(HPointNum);  wrChar(NofVals);  wrChar(StrtPointer);  wrChar(StrtPointer>>8); 
  (*pUx).CRC16out(Ibgn);
}
/****************************************************************************************************/



void FLOBOSS::FormOpcode165rd(char DataBaseNumb)
{ 
  uint Ibgn = formAddress();     wrChar(165); wrChar(4); 
  wrChar(0); wrChar(0); wrChar(DataBaseNumb); wrChar(0);
  (*pUx).CRC16out(Ibgn);
}
/****************************************************************************************************/



void FLOBOSS::FormOpcode180(uint PointAdr)
{ 
  uint Ibgn = formAddress();     wrChar(180); wrChar(4);
  wrChar(1); formPointAdr(PointAdr);
  (*pUx).CRC16out(Ibgn);
}
/****************************************************************************************************/


void FLOBOSS::FormOpcode181(uint PointAdr, char *pVal, char NofByte)
{ 
  uint Ibgn = formAddress();     wrChar(181); wrChar(4+NofByte);
  wrChar(1); formPointAdr(PointAdr);
  while(NofByte) {wrChar(*pVal++); --NofByte;}
  (*pUx).CRC16out(Ibgn);
}
/****************************************************************************************************/



uint FLOBOSS::formAddress(void)
{ 
  uint Ibgn = (*pUx).GetBrdO();
  wrChar(ROCunit); wrChar(ROCgroup); wrChar(HOSTunit); wrChar(HOSTgroup);
  return Ibgn;
}
/****************************************************************************************************/
/****************************************************************************************************/

void FLOBOSS::formPointAdr(uint PointAdr)
{ wrChar((char)(PointAdr>>16)); wrChar((char)(PointAdr>>8)); wrChar((char)PointAdr); }
/****************************************************************************************************/
/****************************************************************************************************/





bool FLOBOSS::askFLOBOSS(void)
{ 
  (*pUx).SetBrdOISR(); (*pUx).StartTransmite();
  return CheckAnswer();
}
/****************************************************************************************************/
/****************************************************************************************************/




/****************************************************************************************************/





void FLOBOSS::GetValue(uint InInd, char *pVar, char Nbytes)
{  while(Nbytes) {*pVar++ = (*pUx).RdBufIn(InInd); (*pUx).next(&InInd); --Nbytes;}  }

void FLOBOSS::RstValue(char *pVar, char Nbytes)
{  while(Nbytes) {*pVar++ = 0; --Nbytes;}  }

void FLOBOSS::GetTime(uint InInd, DataTime *pDT)
{ 
  (*pDT).sec = (*pUx).RdBufIn(InInd);   (*pUx).next(&InInd);
  (*pDT).min = (*pUx).RdBufIn(InInd);   (*pUx).next(&InInd);
  (*pDT).hour= (*pUx).RdBufIn(InInd);   (*pUx).next(&InInd);
  (*pDT).date= (*pUx).RdBufIn(InInd);   (*pUx).next(&InInd);
  (*pDT).mnth= (*pUx).RdBufIn(InInd);   (*pUx).next(&InInd);
  (*pDT).year= (*pUx).RdBufIn(InInd);
}

void FLOBOSS::RstTime(DataTime *pDT)
{ (*pDT).sec = (*pDT).min = (*pDT).hour = (*pDT).date = (*pDT).mnth = (*pDT).year = 0; }


float FLOBOSS::BUFtoFLOAT(void)
{ float val;   char *p;
//  
  p = ((char *)&val)+3;
  *p-- = (*pUx).RdBufIn(InStrt);  (*pUx).next(&InStrt);
  *p-- = (*pUx).RdBufIn(InStrt);  (*pUx).next(&InStrt);
  *p-- = (*pUx).RdBufIn(InStrt);  (*pUx).next(&InStrt);
  *p   = (*pUx).RdBufIn(InStrt);  (*pUx).next(&InStrt);
//
  return val;
}




/****************************************************************************************************/


/****************************************************************************************************/


bool FLOBOSS::CheckAnswer(void)
{ 
  static uint InInd=0;   uint InEnd;
  char poza = pzIdle, NofBytes = 6;
//
  InEnd = InStrt = InInd;
  while( poza!=pzOK && poza!=pzNoAnsw )
   {
     while((*pUx).CountBytes(InStrt,InEnd)<NofBytes)
      {
        if( !(*pUx).RecieveIndI(&InEnd,TimeOutMS) ) {poza=pzNoAnsw; break;}
       }

     switch(poza)
      { 
        case(pzIdle): if(TestAdr(InStrt))
                        {
                          InInd = (*pUx).shift(InStrt,5);
                          NofBytes += 2 + (*pUx).RdBufIn(InInd);
                          poza = pzCRC;
                         }
                       else
                        { InStrt = (*pUx).shift(InStrt,1); }
                     break;
        case(pzCRC):  if( (*pUx).CRC16inN(InStrt,NofBytes) )
                         { poza = pzOK; }
                        else
                         { InStrt = (*pUx).shift(InStrt,1); poza = pzIdle; NofBytes = 6; }
                     break;
       };/*switch(poza)*/
    };/*while( poza!=pzOK || poza!=pzNoAnsw )*/
//
  InInd = InEnd;
  if(poza==pzOK) {return true;} else {return false;}
}

void FLOBOSS::CheckError(void)
{
  if( (*pUx).RdBufIn( (*pUx).shift(InStrt,4) ) == 255 )
    {
      Error = (*pUx).RdBufIn((*pUx).shift(InStrt,6));
      switch(Error)
       {
         case(erSE): AskOpcode17(); break;
        
        }
     }
   else
    { Error = 0; }
}

bool FLOBOSS::TestAdr(uint InInd)
{ 
  if( (*pUx).RdBufIn(InInd)==HOSTunit )
   {
     (*pUx).next(&InInd);
     if( (*pUx).RdBufIn(InInd)==HOSTgroup )
      {
        (*pUx).next(&InInd);
        if( (*pUx).RdBufIn(InInd)==ROCunit )
         {
           (*pUx).next(&InInd);   if( (*pUx).RdBufIn(InInd)==ROCgroup ) return true;
          }
       }
    }
  return false;
}
/*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/